package cn.chencq.moudle.job.task;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;

import cn.chencq.moudle.proxyip.callable.ProxyIpCallable;
import cn.chencq.moudle.proxyip.entity.ProxyIp;
import cn.chencq.moudle.proxyip.service.ProxyIpService;
import cn.chencq.moudle.proxyip.site.PageCrawlerService;
import cn.chencq.moudle.proxyip.site.ProxyListPageParser;

@Component("proxyIpTask")
public class ProxyIpTask {

	private static final Logger logger = LoggerFactory.getLogger(ProxyIpTask.class);
	private static ExecutorService excutorService = new ThreadPoolExecutor(100, 500, 1, TimeUnit.SECONDS,
			new LinkedBlockingDeque<>());

	@Autowired
	private PageCrawlerService pageCrawlerService;

	@Resource(name = "xiaoHeXiaProxyListPageParser")
	private ProxyListPageParser xiaoHeXiaProxyListPageParser;

	@Resource(name = "yunDaiLiProxyListPageParser")
	private ProxyListPageParser yunDaiLiProxyListPageParser;

	@Resource(name = "qiYunProxyListPageParser")
	private ProxyListPageParser qiYunProxyListPageParser;

	@Resource(name = "kuaiDaiLiProxyListPageParser")
	private ProxyListPageParser kuaiDaiLiProxyListPageParser;

	@Resource(name = "ip66ProxyListPageParser")
	private ProxyListPageParser ip66ProxyListPageParser;

	@Resource(name = "xiCiDaiLiProxyListPageParser")
	private ProxyListPageParser xiCiDaiLiProxyListPageParser;
	
	@Autowired
	private ProxyIpService proxyIpService;

	public void spider(String params) {
		if (StringUtils.isBlank(params)) {
			return;
		}

		logger.info("爬虫代理任务参数: " + params);
		JSONObject json = JSONObject.parseObject(params);
		String source = json.getString("source"); // 爬取目标站点名称
		String url = json.getString("url"); // 链接地址
		int type = json.getIntValue("type"); // 爬取类型 0 网页爬虫 1接口爬虫
		int startPage = json.getIntValue("startPage"); // 开始页码, 如果没有默认0
		int entPage = json.getIntValue("endPage"); // 结束页码

		// 根据source获取对应的解析器
		ProxyListPageParser proxyListPageParser = getProxyListPageParser(source);

		List<Callable<List<ProxyIp>>> tasks = new ArrayList<>();
		for (int i = startPage; i <= entPage; i++) {
			String target = url.replace("{page}", String.valueOf(i)); // 链接地址
			tasks.add(new ProxyIpCallable(target, type, proxyListPageParser, pageCrawlerService));
		}

		// 多线程抓取网页并且解析
		List<ProxyIp> result = addTask(tasks);

		// 更新数据库
		proxyIpService.batchSaveOrUpdate(result);
	}

	private ProxyListPageParser getProxyListPageParser(String source) {
		ProxyListPageParser parser = null;
		switch (source) {
		case "xiaohexia":
			parser = xiaoHeXiaProxyListPageParser;
			break;
		case "yundaili":
			parser = yunDaiLiProxyListPageParser;
			break;
		case "qiyun":
			parser = qiYunProxyListPageParser;
			break;
		case "66ip":
			parser = ip66ProxyListPageParser;
			break;
		case "kuaidaili":
			parser = kuaiDaiLiProxyListPageParser;
			break;
		case "xicidaili":
			parser = xiCiDaiLiProxyListPageParser;
			break;
		default:
			break;
		}
		return parser;
	}

	/**
	 * 
	 * @Title: addTask
	 * @Description: 将任务加入到线程池
	 * @param tasks
	 * @return List<ProxyIp>
	 */
	public List<ProxyIp> addTask(List<Callable<List<ProxyIp>>> tasks) {
		List<Future<List<ProxyIp>>> futureList = null;
		List<ProxyIp> result = null;

		try {
			futureList = excutorService.invokeAll(tasks);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		result = new ArrayList<ProxyIp>();
		for (Future<List<ProxyIp>> future : futureList) {
			List<ProxyIp> list = null;
			try {
				list = future.get();
				if (null != list && list.size() > 0) {
					result.addAll(list);
				}
			} catch (Exception e) {
				continue;
			}
		}
		return result;
	}
}
